#include "mtrand.h"
#include "sha256.h"

void mtrand_seed(mtrand_state_t *mt, mtrand_uint32_t seed)
{
	sha256_uint32_t hash[8];
	mtrand_uint32_t i;

	sha256(hash, &seed, sizeof(seed));

	mt->state[0] = hash[0];
	mt->index = 624;
	for(i=1;i<624;i++)
		mt->state[i] = (mtrand_uint32_t)(0x6c078965 * (mt->state[i-1] ^ (mt->state[i-1] >> 30)) + i);
}

static void mtrand_rebuildstate(mtrand_state_t *mt)
{
	int i;
	for(i=0;i<624;i++)
	{
		mtrand_uint32_t y = (mt->state[i] & 0x80000000) | (mt->state[(i+1) % 624] & 0x7fffffff);
		mt->state[i] = mt->state[(i+297) % 624] ^ (y >> 1) ^ ((y&1)*0x9908b0df);
	}
	mt->index = 0;
}

mtrand_uint32_t mtrand_rand_u32(mtrand_state_t *mt)
{
	mtrand_uint32_t y;
	if(mt->index == 624)
		mtrand_rebuildstate(mt);

	y = mt->state[mt->index++];

	// Temper
	y ^= y >> 11;
	y ^= ((y << 7) & 0x9d2c5680);
	y ^= ((y << 15) & 0xefc60000);
	y ^= y >> 18;

	return y;
}
